const BASE64_ENCODE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

/**
 * Base64工具类
 */
export class Base64Util {
  /**
   * 编码
   * @param str 字符串
   */
  static encode(str: string) {
    let c1, c2, c3;
    const len = str.length;
    let i = 0;
    let strin = '';
    while (i < len) {
      c1 = str.charCodeAt(i++) & 0xff;
      if (i == len) {
        strin += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
        strin += BASE64_ENCODE_CHARS.charAt((c1 & 0x3) << 4);
        strin += '==';
        break;
      }
      c2 = str.charCodeAt(i++);
      if (i == len) {
        strin += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
        strin += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
        strin += BASE64_ENCODE_CHARS.charAt((c2 & 0xf) << 2);
        strin += '=';
        break;
      }
      c3 = str.charCodeAt(i++);
      strin += BASE64_ENCODE_CHARS.charAt(c1 >> 2);
      strin += BASE64_ENCODE_CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
      strin += BASE64_ENCODE_CHARS.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6));
      strin += BASE64_ENCODE_CHARS.charAt(c3 & 0x3f);
    }
    return strin;
  }

  /**
   * 解码
   * @param str 字符串
   */
  static decode(str: string) {
    let output = '';
    let chr1, chr2, chr3;
    let enc1, enc2, enc3, enc4;
    let i = 0;
    str = str.replace(/[^A-Za-z0-9+/=]/g, '');
    while (i < str.length) {
      enc1 = BASE64_ENCODE_CHARS.indexOf(str.charAt(i++));
      enc2 = BASE64_ENCODE_CHARS.indexOf(str.charAt(i++));
      enc3 = BASE64_ENCODE_CHARS.indexOf(str.charAt(i++));
      enc4 = BASE64_ENCODE_CHARS.indexOf(str.charAt(i++));
      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;
      output = output + String.fromCharCode(chr1);
      if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
      }
    }
    return utf8_decode(output);

    function utf8_decode(utftext) {
      // utf-8解码
      let string = '';
      let i = 0;
      let c = 0;
      let c1 = 0;
      let c2 = 0;
      while (i < utftext.length) {
        c = utftext.charCodeAt(i);
        if (c < 128) {
          string += String.fromCharCode(c);
          i++;
        } else if (c > 191 && c < 224) {
          c1 = utftext.charCodeAt(i + 1);
          string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
          i += 2;
        } else {
          c1 = utftext.charCodeAt(i + 1);
          c2 = utftext.charCodeAt(i + 2);
          string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
          i += 3;
        }
      }
      return string;
    }
  }
}
